package session.stateless.SCM;

import entity.CRM.LineItem;
import entity.CRM.SaleOrder;
import entity.SCM.Batch;
import entity.SCM.ProductBalance;
import entity.SCM.DeliveryOrder;
import entity.SCM.PackingOrder;
import entity.SCM.PickingOrder;
import entity.SCM.ProductLine;
import entity.SCM.ShippingOrder;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import javaclass.ProductType;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

@Stateless
public class DeliveryOrderBean implements DeliveryOrderBeanLocal {
    
    @PersistenceContext()
    EntityManager em;
    
    DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
    
    @Override
    public List<ProductBalance> getProduct() {
        Query q = em.createQuery("SELECT c FROM ProductBalance c");
        
        return q.getResultList();
    }
    
    @Override
    public Long createDeliveryOrder(Long saleOrderId, List<ProductLine> productLines){
        
        Long returnValue = null;
        
        SaleOrder saleOrder = em.find(SaleOrder.class, saleOrderId);
        if(saleOrder ==null){
            System.out.println("This Sale Order Does Not Exist!");
            return null;
        }
        
        Date date = new Date();
        
        DeliveryOrder deliveryOrder = new DeliveryOrder();
        
        PickingOrder pickingOrder = new PickingOrder();
        pickingOrder.setPickingDate(dateFormat.format(date));
        pickingOrder.setPickingState(PickingOrder.State.Pending);
        em.persist(pickingOrder);
        em.flush();
        
        PackingOrder packingOrder = new PackingOrder();
        packingOrder.setPackingDate(dateFormat.format(date));
        packingOrder.setPackingState(PackingOrder.State.Pending);
        em.persist(packingOrder);
        em.flush();
        
        ShippingOrder shippingOrder = new ShippingOrder();
        shippingOrder.setShippingDate(dateFormat.format(date));
        shippingOrder.setShippingState(ShippingOrder.State.Pending);
        em.persist(shippingOrder);
        em.flush();
        
        deliveryOrder.setDeliveryState(DeliveryOrder.State.Pending);
        deliveryOrder.setDeliveryDate(dateFormat.format(date));
        deliveryOrder.setProductLines(productLines);
        deliveryOrder.setPickingOrder(pickingOrder);
        deliveryOrder.setPackingOrder(packingOrder);
        deliveryOrder.setShippingOrder(shippingOrder);
        deliveryOrder.setSaleOrder(saleOrder);
        Double totalPrice = new Double(0);
        for (ProductLine temp:productLines)
            totalPrice+= temp.getFinalPrice();
        deliveryOrder.setTotalPrice(totalPrice);
        
        em.persist(deliveryOrder);
        em.flush();
        
        pickingOrder.setDeliveryOrder(deliveryOrder);
        packingOrder.setDeliveryOrder(deliveryOrder);
        shippingOrder.setDeliveryOrder(deliveryOrder);
        List<DeliveryOrder> deliveryOrderList = saleOrder.getDeliveryOrders();
        deliveryOrderList.add(deliveryOrder);
        saleOrder.setDeliveryOrders(deliveryOrderList);
        em.flush();
        
        returnValue = deliveryOrder.getId(); 
        return returnValue;
    }

    @Override
    public ProductLine createProductLine(ProductType productType, Long quantity, Double finalPrice) {
        ProductLine productLine = new ProductLine();
        ProductBalance productBalance = em.find(ProductBalance.class, productType);
        productLine.setProduct(productBalance);
        productLine.setQuantity(quantity);
        productLine.setFinalPrice(finalPrice);
        
        em.persist(productLine);
        em.flush();
        
        return productLine;
    }

    @Override
    public boolean processDeliveryOrder(Long deliveryOrderId) {
        
        DeliveryOrder deliveryOrder = em.find(DeliveryOrder.class, deliveryOrderId);
        if(deliveryOrder==null){
            System.out.println("Delivery Order does not exist!");   
            return false;
        }
        else{
            if(deliveryOrder.getDeliveryState().equals(DeliveryOrder.State.Pending)&&
               deliveryOrder.getPickingOrder().getPickingState().equals(PickingOrder.State.Success)&&
               deliveryOrder.getPackingOrder().getPackingState().equals(PackingOrder.State.Success)&&
               deliveryOrder.getShippingOrder().getShippingState().equals(ShippingOrder.State.Success))
            {
                deliveryOrder.setDeliveryState(DeliveryOrder.State.Success);
                //Huanhuan: Please check whether this deliveryOrder is partial or full shipment to update the status of SaleOrder
               
                boolean isCompleted = false;
                Long amount; 
                for(int i=0; i<deliveryOrder.getSaleOrder().getLineItems().size(); i++){
                    isCompleted = false;
                    amount = quantityNeedToDelivery(deliveryOrder.getSaleOrder().getId(), deliveryOrder.getSaleOrder().getLineItems().get(i).getProductPrice().getProductType());
                    if(amount.longValue()==0){
                        isCompleted = true;
                    }         
                    if(!isCompleted){
                        break;
                    }
                }
                
                if(isCompleted){
                    deliveryOrder.getSaleOrder().setStateSaleOrder(SaleOrder.StateSaleOrder.Completed);
                    em.flush();
                }
                em.flush();
                return true;
            }else{
                System.out.println("ProcessDeliveryOrder:: Error Occurs!");
                return false;
            }
        }
    }
    
    
    @Override
    public boolean processPickingOrder(Long pickingId) {
        PickingOrder pickingOrder = em.find(PickingOrder.class, pickingId);
        
        if(pickingOrder==null){
            System.out.println("Picking Order does not exist!");   
            return false;
        }
        else{
            
            SaleOrder saleOrder = pickingOrder.getDeliveryOrder().getSaleOrder();
            if(saleOrder.getStateSaleOrder().equals(SaleOrder.StateSaleOrder.Canceled)){
                Long batchId;
                Batch batch;
                for(int i=0; i<pickingOrder.getProductLineItems().size(); i++){
                    batchId = pickingOrder.getProductLineItems().get(i).getBatch().getId();
                    batch = em.find(Batch.class, batchId);
                    if (batch == null) {
                        System.out.println("This Batch does not exist!");
                        return false;
                    }
                    Long a = pickingOrder.getProductLineItems().get(i).getQuantity();
                    Long b = batch.getQuantity();
                    
                    batch.setQuantity(new Long(a.longValue()+b.longValue()));
                    batch.setStatus(Batch.Status.In);
                    em.flush();
                }
                
                pickingOrder.getDeliveryOrder().getPackingOrder().setPackingState(PackingOrder.State.Deleted);
                pickingOrder.getDeliveryOrder().getShippingOrder().setShippingState(ShippingOrder.State.Deleted);
                pickingOrder.getDeliveryOrder().setDeliveryState(DeliveryOrder.State.Deleted);
                pickingOrder.setPickingState(PickingOrder.State.Deleted);
                em.flush();
                
             return false;  
             
            }else{
            
            if(pickingOrder.getPickingState().equals(PickingOrder.State.Pending)){
                
                pickingOrder.setPickingState(PickingOrder.State.Success);
                
                //Must update the quantityLeft in the LineItem for MRP integration
                for (ProductLine temp_ProductLine: pickingOrder.getDeliveryOrder().getProductLines())
                {
                    Long quantityUsed = temp_ProductLine.getQuantity();
                    System.out.println("processPickingOrder"+quantityUsed);
                    for (LineItem lineItem:pickingOrder.getDeliveryOrder().getSaleOrder().getLineItems())
                        if (lineItem.getProductPrice().getProductType().equals(temp_ProductLine.getProduct().getProductType()))
                        {
                            System.out.println("yeah cam here");
                            lineItem.setQuantityLeft(lineItem.getQuantityLeft()-quantityUsed);
                            System.out.println("test after make changes"+pickingOrder.getDeliveryOrder().getSaleOrder().getLineItems().get(0).getQuantityLeft());
                        }
                }
              
                em.flush();
                return true;
            }else{
                System.out.println("ProcessPackingOrder:: Error Occurs!");
                return false;
            }
            }
        }
    }



    @Override
    public boolean processPackingOrder(Long packingId) {
        PackingOrder packingOrder = em.find(PackingOrder.class, packingId);
        if(packingOrder==null){
            System.out.println("Packing Order does not exist!");   
            return false;
        }
        else{
            if(packingOrder.getPackingState().equals(PackingOrder.State.Pending)){
                
                packingOrder.setPackingState(PackingOrder.State.Success);
                em.flush();
                return true;
            }else{
                System.out.println("ProcessPackingOrder:: Error Occurs!");
                return false;
            }
        }
    }

    @Override
    public boolean processShippingOrder(Long shippingId) {
        ShippingOrder shippingOrder = em.find(ShippingOrder.class, shippingId);
        if(shippingOrder==null){
            System.out.println("Shipping Order does not exist!");   
            return false;
        }
        else{
            if(shippingOrder.getShippingState().equals(ShippingOrder.State.Pending)){
                
                shippingOrder.setShippingState(ShippingOrder.State.Success);
                em.flush();
                return true;
            }else{
                System.out.println("ProcessShippingOrder:: Error Occurs!");
                return false;
            }
        }
    }

    @Override
    public boolean deletedDeliveryOrder(Long deliveryOrderId) {
        
        DeliveryOrder deliveryOrder = em.find(DeliveryOrder.class, deliveryOrderId);
        if(deliveryOrder==null){
            System.out.println("This Delivery Order does not exist!");
            return false;
        }
        else{
            if(deliveryOrder.getPickingOrder()!=null){
                deliveryOrder.getPickingOrder().setPickingState(PickingOrder.State.Deleted);
            }
            if(deliveryOrder.getPackingOrder()!=null){
                deliveryOrder.getPackingOrder().setPackingState(PackingOrder.State.Deleted);
            }
            if(deliveryOrder.getShippingOrder()!=null){
                deliveryOrder.getShippingOrder().setShippingState(ShippingOrder.State.Deleted);
            }
            deliveryOrder.setDeliveryState(DeliveryOrder.State.Deleted);
            em.flush();
            return true;
        }
    }

    @Override
    public boolean deletedPickingOrder(Long pickingId) {
        
        PickingOrder pickingOrder = em.find(PickingOrder.class, pickingId);
        if(pickingOrder==null){
            System.out.println("This Picking Order does not exist!");
            return false;
        }
        else{
            pickingOrder.setPickingState(PickingOrder.State.Deleted);
            em.flush();
            return true;
        }
    }

    @Override
    public boolean deletedPackingOrder(Long packingId) {
        
        PackingOrder packingOrder = em.find(PackingOrder.class, packingId);
        if(packingOrder==null){
            System.out.println("This Packing Order does not exist!");
            return false;
        }
        else{
            packingOrder.setPackingState(PackingOrder.State.Deleted);
            em.flush();
            return true;
        }
    }

    @Override
    public boolean deletedShippingOrder(Long shippingId) {
        
        ShippingOrder shippingOrder = em.find(ShippingOrder.class, shippingId);
        if(shippingOrder==null){
            System.out.println("This Shipping Order does not exist!");
            return false;
        }
        else{
            shippingOrder.setShippingState(ShippingOrder.State.Deleted);
            em.flush();
            return true;
        }
    }

    @Override
    public List<DeliveryOrder> getDeliveryOrder() {
        
        Query q = em.createQuery("SELECT c FROM DeliveryOrder c WHERE c.deliveryState= :deliveryState1 OR c.deliveryState= :deliveryState2");
        q.setParameter("deliveryState1", DeliveryOrder.State.Success);
        q.setParameter("deliveryState2", DeliveryOrder.State.Pending);
        
        return q.getResultList();
    }
    
    @Override
    public List<DeliveryOrder> getPendingDeliveryOrder(){
        
        Query q = em.createQuery("SELECT c FROM DeliveryOrder c WHERE c.deliveryState= :deliveryState");
        q.setParameter("deliveryState", DeliveryOrder.State.Pending);
        
        return q.getResultList();
    }

    @Override
    public List<DeliveryOrder> getSuccessDeliveryOrder() {

        Query q = em.createQuery("SELECT c FROM DeliveryOrder c WHERE c.deliveryState= :deliveryState");
        q.setParameter("deliveryState", DeliveryOrder.State.Success);

        return q.getResultList();


    }

    @Override
    public List<PickingOrder> getPickingOrder() {
        
        Query q =em.createQuery("SELECT c FROM PickingOrder c WHERE c.pickingState = :pickingState1 OR c.pickingState= :pickingState2");
        q.setParameter("pickingState1", PickingOrder.State.Pending);
        q.setParameter("pickingState2", PickingOrder.State.Success);
        
        return q.getResultList();
        
    }
    
    @Override
    public List<PickingOrder> getPendingPickingOrder(){
        
        Query q =em.createQuery("SELECT c FROM PickingOrder c WHERE c.pickingState = :pickingState");
        q.setParameter("pickingState", PickingOrder.State.Pending);
        
        return q.getResultList();
    }

    @Override
    public List<PackingOrder> getPackingOrder() {
        
        Query q =em.createQuery("SELECT c FROM PackingOrder c WHERE c.packingState = :packingState1 OR c.packingState = :packingState2");
        q.setParameter("packingState1", PackingOrder.State.Pending);
        q.setParameter("packingState2", PackingOrder.State.Success);
        
        return q.getResultList();
    }
    
    @Override
    public List<PackingOrder> getPendingPackingOrder() {
        
        Query q =em.createQuery("SELECT c FROM PackingOrder c WHERE c.packingState = :packingState");
        q.setParameter("packingState", PackingOrder.State.Pending);
        
        return q.getResultList();
    }

    @Override
    public List<ShippingOrder> getShippingOrder() {
        
        Query q =em.createQuery("SELECT c FROM ShippingOrder c WHERE c.shippingState = :shippingState1 OR c.shippingState= :shippingState2");
        q.setParameter("shippingState1", ShippingOrder.State.Pending);
        q.setParameter("shippingState2", ShippingOrder.State.Success);
        
        return q.getResultList();
    }
    
    @Override
    public List<ShippingOrder> getPendingShippingOrder() {
        
        Query q =em.createQuery("SELECT c FROM ShippingOrder c WHERE c.shippingState = :shippingState");
        q.setParameter("shippingState", ShippingOrder.State.Pending);
        
        return q.getResultList();
    }
    
    @Override
    public Long quantityNeedToDelivery(Long saleOrderId, ProductType productType){
        
        SaleOrder saleOrder = em.find(SaleOrder.class, saleOrderId);
        if(saleOrder == null){
            System.out.println("This SaleOrder Does Not Exist!");
            return null;
        }
        
        long a = 0;
        
        for(int i=0; i<saleOrder.getLineItems().size(); i++){
            if(saleOrder.getLineItems().get(i).getProductPrice().getProductType().equals(productType)){
                a = saleOrder.getLineItems().get(i).getLineItemQuantity().longValue();
            }
        }
        
        long b = 0;
        Long temp = null;
        
        for(int i=0; i<saleOrder.getDeliveryOrders().size();i++){
            for(int j=0; j<saleOrder.getDeliveryOrders().get(i).getProductLines().size(); j++){
                if(saleOrder.getDeliveryOrders().get(i).getProductLines().get(j).getProduct().getProductType().equals(productType)){
                    temp = saleOrder.getDeliveryOrders().get(i).getProductLines().get(j).getQuantity();
                }
            }
            if(temp ==null){
                temp = new Long(0);
            }
            
            b += temp.longValue();
        }
        
        Long validQuantity = new Long(a-b);
        
        return validQuantity;
    }

    
}
